
let Methods = require('./methods');

function asset(value, msg) {
    if (!value) {
        throw new Error(`error:${msg}`);
    }
}

/**
 * 区块摒除法:
 *  步骤是1. 通过当前盘面,去减少可能的值,
 *  当发现某个cell里面就剩下一个可能值的时候,就可以给出结果了.
 *
 *
 *  主要作用就是用来排除 笔记:
 *
 **/

function getInsection(cells) {
    // cells.length 为2 或者3
    // 在每一个 cell 中都包含
    let arr = Array.from(cells[0].getMaybeArr());

    let rms = []; // 需要被删除的
    arr.forEach(value=>{
        for(let i = 1,len = cells.length; i < len; ++i){
            let maybeArr = cells[i].getMaybeArr();
            if(maybeArr.indexOf(value) < 0){
                rms.push(value);
                break;
            }
        }
    });

    // 从 arr 中删除 rms
    rms.forEach(value=>{
        let idx = arr.indexOf(value);
        asset(idx >=0, `idx:${idx} 应该 >= 0`);
        arr.splice(idx,1);
    });

    return arr;
}

function getSpectArr(rowOrColCells,otherCells) {
    let sameValueArr = getInsection(rowOrColCells);

    // 同时 otherCells 中不能出现 sameValueArr里面的值
    let rmSet = new Set();
    otherCells.forEach(cell=>{
        let maybeArr = cell.getMaybeArr();
        maybeArr.forEach(value=>{
            rmSet.add(value);
        });
    });

    rmSet.forEach(value=>{
        let idx = sameValueArr.indexOf(value);
        if(idx >= 0){
            sameValueArr.splice(idx,1);
        }
    });
    return sameValueArr;
}

function qkBC(boardInfo,cells,lstGongCells) {

    let board = boardInfo.board;

    // let gongCount = borardInfo.gongCount;
    let gongRowCount = boardInfo.gongRowCount;
    let gongColCount = boardInfo.gongColCount;

    // 对宫 进行检查
    for(let i= 0,len = lstGongCells.length; i < len; ++i){
        let gongCells = lstGongCells[i];

        // 检查是否 有cell 在同一 行/列
        if(gongCells.length < 2){
            continue;
        }

        let gongIdx = gongCells[0].gongIdx;
        let startIds = boardInfo.getGongStartIdx(gongIdx);

        // 对宫里进行 行检查
        for(let m = 0; m < gongRowCount;++m){
            let curRowIdx = startIds.x + m;

            let rowCells = [];
            let otherCells = [];
            gongCells.forEach(cell=>{
                if(cell.rowIdx === curRowIdx){
                    rowCells.push(cell);
                }else{
                    otherCells.push(cell);
                }
            });
            if(rowCells.length < 2){
                continue;
            }

            // 判断是否存在某个数 只能在此行存在
            // 即 某个数 不能在此宫内的其他行存在. 同时不能在此行的其他列存在
            let specArr = getSpectArr(rowCells,otherCells);
            if(specArr.length < 1){
                continue;
            }

            // 说明了 specArr 里面的数 只可能出现在当前行里面
            // 下面就可以做剔除操作了:
            // 对 board 进行当前行剔除
            let lstInRowCells = cells.filter(cell=>{
                return cell.rowIdx === curRowIdx && cell.gongIdx !== gongIdx;
            });
            if(lstInRowCells && lstInRowCells.length > 0){
                // 对 specArr 进行剔除
                let weeds = []; // 存储剔除的内容
                lstInRowCells.forEach(cell=>{
                    let maybeArr = cell.getMaybeArr();
                    specArr.forEach(value=>{
                        let idx = maybeArr.indexOf(value);
                        if(idx >= 0){
                            maybeArr.splice(idx,1); // 剔除,需要记录下来
                            weeds.push({
                                x:cell.rowIdx,
                                y:cell.colIdx,
                                value:value, // 这里表示剔除的值
                                type:Methods.QKBC.GONG_ROW
                            });
                        }
                    });
                });

                if(weeds.length > 0){
                    return weeds; // 剔除成功
                }
            }
        }

        // 对宫里进行 列检查
        for(let n = 0; n < gongColCount;++n){
            let curColIdx = startIds.y + n;

            let colCells = [];
            let otherCells = [];
            gongCells.forEach(cell=>{
                if(cell.colIdx === curColIdx){
                    colCells.push(cell);
                }else{
                    otherCells.push(cell);
                }
            });
            if(colCells.length < 2){
                continue
            }
            let specArr = getSpectArr(colCells,otherCells);
            if(specArr.length < 1){
                continue;
            }

            let lstInColCells = cells.filter(cell=>{
                return cell.colIdx === curColIdx && cell.gongIdx !== gongIdx;
            });

            if(lstInColCells && lstInColCells.length > 0){
                // 对 specArr 进行剔除
                let weeds = []; // 存储剔除的内容
                lstInColCells.forEach(cell=>{
                    let maybeArr = cell.getMaybeArr();
                    specArr.forEach(value=>{
                        let idx = maybeArr.indexOf(value);
                        if(idx >= 0){
                            maybeArr.splice(idx,1); // 剔除,需要记录下来
                            weeds.push({
                                x:cell.rowIdx,
                                y:cell.colIdx,
                                value:value, // 这里表示剔除的值
                                type:Methods.QKBC.GONG_COL
                            });
                        }
                    });
                });

                if(weeds.length > 0){
                    return weeds; // 剔除成功
                }
            }
        }
    }

    // 对行 进行检查.
    let boardSize = boardInfo.boardSize;
    for(let i = 0; i < board.length;++i){
        let rowValus = board[i];

        // 从 1-9 开始测试.
        for(let num = 1; num <= boardSize; ++num){
            // 计算 num 可能在当前行的 哪几个cell
            if(rowValus.indexOf(num) >= 0){
                continue;
            }
            let rowCells = cells.filter(cell=>{
                let maybeArr = cell.getMaybeArr();
                return cell.rowIdx === i && maybeArr.indexOf(num) >= 0;
            });
            if(isCellsInSameGong(rowCells)){
                // 剔除当前宫里面其他 cell 里面包含的 num 值
                let gongIdx = rowCells[0].gongIdx;
                let gongCells = lstGongCells[gongIdx];
                let otherCells = gongCells.filter(cell=>{
                    return cell.rowIdx !== i;
                });
                if(otherCells && otherCells.length > 0){
                    let weeds = [];
                    otherCells.forEach(cell=>{
                        let maybeArr = cell.getMaybeArr();
                        if(maybeArr.indexOf(num) >= 0){
                            weeds.push({
                               x:cell.rowIdx,
                               y:cell.colIdx,
                               value:num, // 剔除的值
                                type:Methods.QKBC.ROW
                            });
                        }
                    });
                    if(weeds.length > 0){
                        return weeds;
                    }
                }
            }
        }
    }

    // 对列 进行检查
    for(let j = 0; j < board[0].length; ++j){
        let colValues = [];
        for(let i = 0; i < board.length;++i){
            if(board[i][j] > 0){
                colValues.push(board[i][j]);
            }
        }

        // 从1-9开始测试
        for(let num = 1; num <= boardSize; ++num){
            if(colValues.indexOf(num) >= 0){
                continue;
            }
            let colCells = cells.filter(cell=>{
               let maybeArr = cell.getMaybeArr();
               return cell.colIdx === j && maybeArr.indexOf(num) >= 0;
            });
            if(isCellsInSameGong(colCells)){
                // 剔除当前宫里面其他 cell 里面包含的 num 值
                let gongIdx = colCells[0].gongIdx;
                let gongCells = lstGongCells[gongIdx];
                let otherCells = gongCells.filter(cell=>{
                    return cell.colIdx !== j;
                });
                if(otherCells && otherCells.length > 0){
                    let weeds = [];
                    otherCells.forEach(cell=>{
                        let maybeArr = cell.getMaybeArr();
                        if(maybeArr.indexOf(num) >= 0){
                            weeds.push({
                                x:cell.rowIdx,
                                y:cell.colIdx,
                                value:num, // 剔除的值
                                type:Methods.QKBC.COL
                            });
                        }
                    });
                    if(weeds.length > 0){
                        return weeds;
                    }
                }
            }
        }
    }

    return null;
}


/**
 *
 * @param cells {Array | null}
 * @return {boolean}
 */
function isCellsInSameGong(cells){
    // 注意 cells.length 不会为1, 因为如果为1的话  前面的算法就应该可以给出提示
    if(!cells || cells.length < 2){
        return false;
    }
    let gongIdx = cells[0].gongIdx;
    for(let i = 1; i < cells.length; ++i){
        if(cells[i].gongIdx !== gongIdx){
            return false;
        }
    }
    return true;
}

module.exports = qkBC;
